package com.example.lark.im.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.example.api.common.utils.EncryptionUtils;
import com.example.api.common.utils.HttpUtils;
import com.example.lark.common.configuration.properties.LarkSuiteConfigurationProperties;
import com.example.lark.im.result.LarkSuiteJsapiTicketResult;
import com.example.lark.im.result.LarkSuiteTenantAccessTokenResult;
import com.example.lark.im.service.LarkSuiteService;
import com.example.lark.im.vo.resp.LarkSuiteJsapiTicketRespVO;
import com.lark.oapi.Client;
import com.lark.oapi.core.request.RequestOptions;
import com.lark.oapi.service.application.v6.enums.UserIdTypeEnum;
import com.lark.oapi.service.application.v6.model.AppBadge;
import com.lark.oapi.service.application.v6.model.SetAppBadgeReq;
import com.lark.oapi.service.application.v6.model.SetAppBadgeResp;
import com.lark.oapi.service.contact.v3.model.BatchGetIdUserReq;
import com.lark.oapi.service.contact.v3.model.BatchGetIdUserReqBody;
import com.lark.oapi.service.contact.v3.model.BatchGetIdUserResp;
import com.lark.oapi.service.contact.v3.model.BatchGetIdUserRespBody;
import com.lark.oapi.service.contact.v3.model.UserContactInfo;
import com.lark.oapi.service.im.v1.model.CreateMessageReq;
import com.lark.oapi.service.im.v1.model.CreateMessageReqBody;
import com.lark.oapi.service.im.v1.model.CreateMessageResp;
import com.lark.oapi.service.im.v1.model.CreateMessageRespBody;
import com.lark.oapi.service.im.v1.model.PatchMessageReq;
import com.lark.oapi.service.im.v1.model.PatchMessageReqBody;
import com.lark.oapi.service.im.v1.model.PatchMessageResp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;

import static com.alibaba.fastjson2.JSON.parseObject;

@Slf4j
@Service
public class LarkSuiteServiceImpl implements LarkSuiteService {

    @Autowired
    private LarkSuiteConfigurationProperties larkSuiteConfigurationProperties;

    @Override
    public String getTenantAccessToken() {
        try {
            HttpUtils.HttpRequest httpRequest = new HttpUtils.HttpRequest();
            httpRequest.setUrl(getFeiShuTenantAccessTokenUrl());
            httpRequest.setBodyParameters(getAuthParam());
            String responseJson = HttpUtils.post(httpRequest);

            LarkSuiteTenantAccessTokenResult larkSuiteTenantAccessTokenResult = parseObject(responseJson, LarkSuiteTenantAccessTokenResult.class);
            log.info("larkSuiteTenantAccessTokenResult == {}", JSON.toJSONString(larkSuiteTenantAccessTokenResult));
            if (larkSuiteTenantAccessTokenResult == null) {
                throw new RuntimeException("获取飞书AccessToken失败：响应体为空");
            }
            if (!larkSuiteTenantAccessTokenResult.isSuccess()) {
                log.info("异常响应：[code = {}, msg = {}]", larkSuiteTenantAccessTokenResult.getCode(), larkSuiteTenantAccessTokenResult.getMsg());
                throw new RuntimeException("获取飞书AccessToken失败：返回异常响应");
            }
            return larkSuiteTenantAccessTokenResult.getTenantAccessToken();

        } catch (RuntimeException e) {
            log.error(e.getMessage(), e);
            throw e;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("获取飞书AccessToken失败");
        }
    }

    @Override
    public LarkSuiteJsapiTicketRespVO getJsapiTicket(String url) {
        if (StringUtils.isBlank(url)) {
            throw new RuntimeException("URL不能为空");
        }
        String jsapiTicket = getJsapiTicket();
        String nonceStr = UUID.randomUUID().toString().substring(0, 16);
        long timestamp = System.currentTimeMillis();
        String verifyStr = "jsapi_ticket=" + jsapiTicket
                + "noncestr=" + nonceStr
                + "timestamp=" + timestamp
                + "url=" + url;
        String sha1Signature = EncryptionUtils.sha1(verifyStr);

        LarkSuiteJsapiTicketRespVO larkSuiteJsapiTicketRespVO = new LarkSuiteJsapiTicketRespVO();
        larkSuiteJsapiTicketRespVO.setAppId(getAppId());
        larkSuiteJsapiTicketRespVO.setTimestamp(timestamp);
        larkSuiteJsapiTicketRespVO.setNonceStr(nonceStr);
        larkSuiteJsapiTicketRespVO.setSignature(sha1Signature);
        return larkSuiteJsapiTicketRespVO;
    }

    private String getJsapiTicket() {
        HttpUtils.HttpRequest httpRequest = new HttpUtils.HttpRequest();
        httpRequest.setUrl(getFeiShuJsapiTicketUrl());
        httpRequest.setBodyParameters(getAuthParam());
        httpRequest.setHttpHeaders(getHttpHeadersWithAuthorization());
        String responseJson = HttpUtils.post(httpRequest);

        LarkSuiteJsapiTicketResult larkSuiteJsapiTicketResult = JSON.parseObject(responseJson, LarkSuiteJsapiTicketResult.class);
        log.info("larkSuiteJsapiTicketResult = {}", JSON.toJSONString(larkSuiteJsapiTicketResult));
        if (larkSuiteJsapiTicketResult == null) {
            throw new RuntimeException("获取 jsapi_ticket[临时调用凭证] 失败：响应体为空");
        }
        if (!larkSuiteJsapiTicketResult.isSuccess()) {
            log.info("异常响应：[code = {}, msg = {}]", larkSuiteJsapiTicketResult.getCode(), larkSuiteJsapiTicketResult.getMsg());
            throw new RuntimeException("获取 jsapi_ticket[临时调用凭证] 失败：返回异常响应");
        }
        return larkSuiteJsapiTicketResult.getData().getTicket();
    }

    @Override
    public BatchGetIdUserRespBody getUserIdByMobileOrEmail(BatchGetIdUserReq batchGetIdUserReq) {
        checkBatchGetIdUserReq(batchGetIdUserReq);
        log.info("emails = {}, mobiles = {}", batchGetIdUserReq.getBatchGetIdUserReqBody().getEmails(), batchGetIdUserReq.getBatchGetIdUserReqBody().getMobiles());
        try {
            // 构建client
            Client client = Client.newBuilder(getAppId(), getAppSecret()).build();
            // 创建请求对象
            BatchGetIdUserReq req = BatchGetIdUserReq.newBuilder()
                    .userIdType(batchGetIdUserReq.getUserIdType())
                    .batchGetIdUserReqBody(BatchGetIdUserReqBody.newBuilder()
                            .emails(distinctNumber(batchGetIdUserReq.getBatchGetIdUserReqBody().getEmails()))
                            .mobiles(distinctNumber(batchGetIdUserReq.getBatchGetIdUserReqBody().getMobiles()))
                            .build())
                    .build();
            // 发起请求
            BatchGetIdUserResp batchGetIdUserResp = client.contact().v3().user().batchGetId(req, RequestOptions.newBuilder().build());
            log.info("batchGetIdUserResp = {}", JSON.toJSONString(batchGetIdUserResp));
            if (!batchGetIdUserResp.success()) {
                throw new RuntimeException("[飞书]通过手机号或邮箱获取用户ID失败：" + batchGetIdUserResp.getCode() + " - " + batchGetIdUserResp.getMsg());
            }
            return batchGetIdUserResp.getData();

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("[飞书]通过手机号或邮箱获取用户ID失败");
        }
    }

    /**
     * 必填项校验BatchGetIdUserReq
     *
     * @param batchGetIdUserReq BatchGetIdUserReq对象
     */
    private void checkBatchGetIdUserReq(BatchGetIdUserReq batchGetIdUserReq) {
        if (batchGetIdUserReq == null || batchGetIdUserReq.getBatchGetIdUserReqBody() == null) {
            throw new RuntimeException("请求参数不能为空");
        }
        if (StringUtils.isBlank(batchGetIdUserReq.getUserIdType())) {
            throw new RuntimeException("返回的用户ID类型不能为空");
        }
        BatchGetIdUserReqBody batchGetIdUserReqBody = batchGetIdUserReq.getBatchGetIdUserReqBody();
        if (batchGetIdUserReqBody.getEmails() == null) {
            batchGetIdUserReqBody.setEmails(new String[]{});
        }
        if (batchGetIdUserReqBody.getMobiles() == null) {
            batchGetIdUserReqBody.setMobiles(new String[]{});
        }
        if (batchGetIdUserReqBody.getEmails().length == 0 && batchGetIdUserReqBody.getMobiles().length == 0) {
            throw new RuntimeException("用户邮箱和手机号不能都为空");
        }
        if (batchGetIdUserReqBody.getEmails().length > 50 || batchGetIdUserReqBody.getMobiles().length > 50) {
            throw new RuntimeException("用户邮箱和手机号数量均不能大于50个");
        }
    }

    private String[] distinctNumber(String[] numbers) {
        if (numbers == null || numbers.length == 0) {
            return new String[]{};
        }
        return Arrays.stream(numbers).distinct().toArray(String[]::new);
    }

    @Override
    public CreateMessageRespBody sendMessage(CreateMessageReq createMessageReq) {
        checkCreateMessageReq(createMessageReq);
        try {
            // 构建client
            Client client = Client.newBuilder(getAppId(), getAppSecret()).build();
            // 创建请求对象
            CreateMessageReq req = CreateMessageReq.newBuilder()
                    .receiveIdType(createMessageReq.getReceiveIdType())
                    .createMessageReqBody(CreateMessageReqBody.newBuilder()
                            .receiveId(createMessageReq.getCreateMessageReqBody().getReceiveId())
                            .msgType(createMessageReq.getCreateMessageReqBody().getMsgType())
                            .content(createMessageReq.getCreateMessageReqBody().getContent())
                            .uuid(createMessageReq.getCreateMessageReqBody().getUuid())
                            .build())
                    .build();
            // 发起请求
            CreateMessageResp createMessageResp = client.im().v1().message().create(req, RequestOptions.newBuilder().build());
            log.info("createMessageResp = {}", JSON.toJSONString(createMessageResp));
            if (!createMessageResp.success()) {
                throw new RuntimeException("[飞书]发送消息失败：" + createMessageResp.getCode() + " - " + createMessageResp.getMsg());
            }
            return createMessageResp.getData();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("[飞书]发送消息失败");
        }
    }

    /**
     * 必填项校验CreateMessageReq
     *
     * @param createMessageReq CreateMessageReq对象
     */
    private void checkCreateMessageReq(CreateMessageReq createMessageReq) {
        if (createMessageReq == null || createMessageReq.getCreateMessageReqBody() == null) {
            throw new RuntimeException("请求参数不能为空");
        }
        if (StringUtils.isBlank(createMessageReq.getReceiveIdType())) {
            throw new RuntimeException("消息接收者ID类型不能为空");
        }
        CreateMessageReqBody createMessageReqBody = createMessageReq.getCreateMessageReqBody();
        if (StringUtils.isBlank(createMessageReqBody.getReceiveId())) {
            throw new RuntimeException("消息接收者的ID不能为空");
        }
        if (StringUtils.isBlank(createMessageReqBody.getMsgType())) {
            throw new RuntimeException("消息类型不能为空");
        }
        if (StringUtils.isBlank(createMessageReqBody.getContent())) {
            throw new RuntimeException("消息内容不能为空");
        }
    }

    @Override
    public void updateMessageCardFromApplication(PatchMessageReq patchMessageReq) {
        checkPatchMessageReq(patchMessageReq);
        try {
            // 构建client
            Client client = Client.newBuilder(getAppId(), getAppSecret()).build();
            // 创建请求对象
            PatchMessageReq req = PatchMessageReq.newBuilder()
                    .messageId(patchMessageReq.getMessageId())
                    .patchMessageReqBody(PatchMessageReqBody.newBuilder()
                            .content(patchMessageReq.getPatchMessageReqBody().getContent())
                            .build())
                    .build();
            // 发起请求
            PatchMessageResp patchMessageResp = client.im().v1().message().patch(req, RequestOptions.newBuilder().build());
            log.info("patchMessageResp = {}", JSON.toJSONString(patchMessageResp));
            if (!patchMessageResp.success()) {
                throw new RuntimeException("[飞书]更新应用发送的消息失败：" + patchMessageResp.getCode() + " - " + patchMessageResp.getMsg());
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("[飞书]更新应用发送的消息失败");
        }
    }

    /**
     * 必填项校验PatchMessageReq
     *
     * @param patchMessageReq PatchMessageReq对象
     */
    private void checkPatchMessageReq(PatchMessageReq patchMessageReq) {
        if (patchMessageReq == null || patchMessageReq.getPatchMessageReqBody() == null) {
            throw new RuntimeException("请求参数不能为空");
        }
        if (StringUtils.isBlank(patchMessageReq.getMessageId())) {
            throw new RuntimeException("待更新的消息的ID不能为空");
        }
        PatchMessageReqBody patchMessageReqBody = patchMessageReq.getPatchMessageReqBody();
        if (StringUtils.isEmpty(patchMessageReqBody.getContent())) {
            throw new RuntimeException("消息内容不能为空");
        }
    }

    @Override
    public void updateAppBadge(SetAppBadgeReq setAppBadgeReq) {
        checkSetAppBadgeReq(setAppBadgeReq);
        try {
            // 构建client
            Client client = Client.newBuilder(getAppId(), getAppSecret()).build();
            // 创建请求对象
            SetAppBadgeReq req = SetAppBadgeReq.newBuilder()
                    .userIdType(setAppBadgeReq.getUserIdType())
                    .appBadge(AppBadge.newBuilder()
                            .userId(setAppBadgeReq.getAppBadge().getUserId())
                            .version(String.valueOf(System.currentTimeMillis()))
                            .extra(setAppBadgeReq.getAppBadge().getExtra())
                            .pc(setAppBadgeReq.getAppBadge().getPc())
                            .mobile(setAppBadgeReq.getAppBadge().getMobile())
                            .build())
                    .build();
            // 发起请求
            SetAppBadgeResp setAppBadgeResp = client.application().v6().appBadge().set(req, RequestOptions.newBuilder().build());
            log.info("setAppBadgeResp = {}", JSON.toJSONString(setAppBadgeResp));
            if (!setAppBadgeResp.success()) {
                throw new RuntimeException("[飞书]更新应用红点失败：" + setAppBadgeResp.getCode() + " - " + setAppBadgeResp.getMsg());
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("[飞书]更新应用红点失败");
        }
    }

    /**
     * 必填项校验SetAppBadgeReq
     *
     * @param setAppBadgeReq SetAppBadgeReq对象
     */
    private void checkSetAppBadgeReq(SetAppBadgeReq setAppBadgeReq) {
        if (setAppBadgeReq == null || setAppBadgeReq.getAppBadge() == null) {
            throw new RuntimeException("请求参数不能为空");
        }
        if (StringUtils.isBlank(setAppBadgeReq.getUserIdType())) {
            // 更新角标接口默认使用的是${open_id}，若需要使用${user_id}，则必须指定userIdType="user_id"
            setAppBadgeReq.setUserIdType(UserIdTypeEnum.USER_ID.getValue());
        }
        AppBadge appBadge = setAppBadgeReq.getAppBadge();
        if (StringUtils.isBlank(appBadge.getUserId())) {
            throw new RuntimeException("用户ID不能为空");
        }
    }

    /**
     * 获取认证参数
     */
    private JSONObject getAuthParam() {
        JSONObject paramJson = new JSONObject();
        paramJson.put("app_id", getAppId());
        paramJson.put("app_secret", getAppSecret());
        return paramJson;
    }

    /**
     * 获取飞书 应用唯一标识
     */
    private String getAppId() {
        return larkSuiteConfigurationProperties.getAuth().getAppId();
//        return "cli_a6b702efc1e5500c";
    }

    /**
     * 获取飞书 应用秘钥
     */
    private String getAppSecret() {
        return larkSuiteConfigurationProperties.getAuth().getAppSecret();
//        return "dqIyHpeCd7zFIw447b0zweBdTTQqdAAv";
    }

    /**
     * 获取飞书 TenantAccessToken 的URL
     */
    private String getFeiShuTenantAccessTokenUrl() {
        return larkSuiteConfigurationProperties.getApiUrl().getFeiShuTenantAccessTokenUrl();
//        return "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal";
    }

    /**
     * 获取飞书 JSAPI临时凭证 的URL
     */
    private String getFeiShuJsapiTicketUrl() {
        return larkSuiteConfigurationProperties.getApiUrl().getFeiShuJsapiTicketUrl();
//        return "https://open.feishu.cn/open-apis/jssdk/ticket/get";
    }

    /**
     * 获取请求头
     */
    private HttpHeaders getHttpHeaders() {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("Content-Type", "application/json; charset=utf-8");
        return httpHeaders;
    }

    /**
     * 获取带有 Authorization 的请求头
     */
    private HttpHeaders getHttpHeadersWithAuthorization() {
        HttpHeaders httpHeaders = getHttpHeaders();
        httpHeaders.add("Authorization", "Bearer " + getTenantAccessToken());
        return httpHeaders;
    }


    private List<String> getUserIds(BatchGetIdUserReq batchGetIdUserReq) {
        if (batchGetIdUserReq == null) {
            throw new RuntimeException("请求参数不能为空");
        }
        if (StringUtils.isBlank(batchGetIdUserReq.getUserIdType())) {
            // 默认获取 user_id
            batchGetIdUserReq.setUserIdType(UserIdTypeEnum.USER_ID.getValue());
        }
        BatchGetIdUserRespBody batchGetIdUserRespBody = getUserIdByMobileOrEmail(batchGetIdUserReq);
        if (batchGetIdUserRespBody == null) {
            throw new RuntimeException("通过手机号或邮箱获取用户ID失败：响应体为空");
        }
        UserContactInfo[] userList = batchGetIdUserRespBody.getUserList();
        if (userList == null || userList.length == 0) {
            throw new RuntimeException("通过手机号或邮箱获取用户ID为空");
        }
        List<String> userIds = Arrays.stream(userList).map(UserContactInfo::getUserId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        log.info("获取到的用户ID userIds = {}", userIds);
        return userIds;
    }

}
